<?php
namespace app\common\lib;

class IDCardAuth
{
    /**
     * 正则表达式验证身份证
     * @author 贺强
     * @time   2020-05-09 16:13:13
     * @param string $idNo 身份证号
     * @param string $name 姓名
     * @return false|string
     */
    public static function checkIdCard($idNo = '', $name = '')
    {
        $res = ['code' => 400, 'message' => '身份证非法', 'idNo' => '', 'name' => '', 'age' => 0];
        // 正则表达式验证身份证
        $reg18 = '/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/';
        $reg15 = '/^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$/';
        $flag1 = preg_match($reg18, $idNo);
        $flag2 = preg_match($reg15, $idNo);
        if ($flag1 || $flag2) {
            $res['code'] = 200;
            $res['message'] = '';
            $res['idNo'] = $idNo;
            $res['name'] = $name;
            // 计算年龄
            $birthday = substr($idNo, 6, 8);
            $date1 = date_create($birthday);
            $date2 = date_create(date('Ymd'));
            $cha = date_diff($date1, $date2);
            $res['age'] = $cha->y;
            $gender = intval(substr($idNo, 16, 1));
            if ($gender % 2) {
                $res['gender'] = 'M';
            } else {
                $res['gender'] = 'F';
            }
        }
        return json_encode($res);
    }

    /**
     * 检验身份证是否合法
     * @author 贺强
     * @time   2019-11-29 14:08:45
     * @param string $idNo 身份证号
     * @param string $name 姓名
     * @return bool|string
     */
    public static function checkIdCard2($idNo = '', $name = '')
    {
        $url = "https://idenauthen.market.alicloudapi.com/idenAuthentication";
        $method = "POST";
        $appcode = "bb8499a4c67e4659a9f3f5767531d574";
        $headers = [];
        array_push($headers, "Authorization:APPCODE " . $appcode);
        //根据API的要求，定义相对应的Content-Type
        array_push($headers, "Content-Type" . ":" . "application/x-www-form-urlencoded; charset=UTF-8");
        $body = "idNo=$idNo&name=$name";
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, false);
        //curl_setopt($curl, CURLOPT_HEADER, true);   // 如不输出json, 请打开这行代码，打印调试头部状态码。
        //状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
        $out_put = curl_exec($curl);
        return $out_put;
    }

    /**
     * 验证身份证是否有效
     * @param string $IDCard 身份证号
     * @return boolean
     */
    public static function validateIDCard($IDCard)
    {
        if (strlen($IDCard) == 18) {
            return self::check18IDCard($IDCard);
        } elseif ((strlen($IDCard) == 15)) {
            $IDCard = self::convertIDCard15to18($IDCard);
            return self::check18IDCard($IDCard);
        } else {
            return false;
        }
    }

    /**
     * 计算身份证的最后一位验证码,根据国家标准GB 11643-1999
     * @param string $IDCardBody
     * @return boolean|string
     */
    public static function calcIDCardCode($IDCardBody)
    {
        if (strlen($IDCardBody) != 17) {
            return false;
        }
        //加权因子
        $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        //校验码对应值
        $code = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
        $checksum = 0;
        for ($i = 0; $i < strlen($IDCardBody); $i++) {
            $checksum += substr($IDCardBody, $i, 1) * $factor[$i];
        }
        return $code[$checksum % 11];
    }

    /**
     * 将15位身份证升级到18位
     * @param string $IDCard 身份证号
     * @return boolean|string
     */
    public static function convertIDCard15to18($IDCard)
    {
        if (strlen($IDCard) != 15) {
            return false;
        } else {
            // 如果身份证顺序码是996 997 998 999，这些是为百岁以上老人的特殊编码
            if (array_search(substr($IDCard, 12, 3), ['996', '997', '998', '999']) !== false) {
                $IDCard = substr($IDCard, 0, 6) . '18' . substr($IDCard, 6, 9);
            } else {
                $IDCard = substr($IDCard, 0, 6) . '19' . substr($IDCard, 6, 9);
            }
        }
        $IDCard = $IDCard . self::calcIDCardCode($IDCard);
        return $IDCard;
    }

    /**
     * 18位身份证校验码有效性检查
     * @param string $IDCard
     * @return boolean
     */
    public static function check18IDCard($IDCard)
    {
        if (strlen($IDCard) != 18) {
            return false;
        }
        $IDCardBody = substr($IDCard, 0, 17);             //身份证主体
        $IDCardCode = strtoupper(substr($IDCard, 17, 1)); //身份证最后一位的验证码
        return self::calcIDCardCode($IDCardBody) == $IDCardCode;
    }

    /**
     * 根据身份证判断,是否满足年龄条件
     * @param string  $IDCard 身份证
     * @param integer $minAge 最小年龄
     * @return bool
     */
    public static function isMeetAgeByIDCard($IDCard, $minAge)
    {
        $ret = self::validateIDCard($IDCard);
        if ($ret === false) {
            return false;
        }
        if (strlen($IDCard) <= 15) {
            $IDCard = self::convertIDCard15to18($IDCard);
        }
        $year = date('Y') - substr($IDCard, 6, 4);
        $monthDay = date('md') - substr($IDCard, 10, 4);
        return $year > $minAge || $year == $minAge && $monthDay >= 0;
    }
}
